/*******************************************************************************
  * 文件：StateMachine.c
  * 作者：djy
  * 版本：v1.0.0
  * 日期：2021.01.14
  * 说明：面向对象的状态机
*******************************************************************************/
#include "StateMachine.h"

/*******************************************************************************
  * 函数名  ：GetStateOps
  * 功  能  ：获取状态机操作
  * 参  数  ：StateMachine_ts *psStateMachine：状态机
  *           S16 state：状态机状态
  * 返回值  ：StateMachineOps_ts：状态机对应的Ops
  * 说  明  ：无
*******************************************************************************/
static const StateMachineOps_ts *GetStateOps(StateMachine_ts *psStateMachine,S16 state)
{
    S16 i;

    for(i = 0; i < psStateMachine->SMOpsCount; i++)
    {
        if(((psStateMachine->FirstSMOp)+i)->State == state)
        {
            return ((psStateMachine->FirstSMOp)+i);
        }
    }

    return NULL;
}

/*******************************************************************************
  * 函数名  ：StateMchine_TimingHandler
  * 功  能  ：状态机定时重试处理函数
  * 参  数  ：无
  * 返回值  ：无
  * 说  明  ：定时重试状态机
*******************************************************************************/
static void StateMchine_TimingRetryHandler(U32 arg)
{
    // 获取当前状态机
    StateMachine_ts *psStateMachine = (StateMachine_ts *)arg;

    // 停止定时器
    OS_TimerStop(&psStateMachine->sTimer);

    // 定时时间到，立刻重试当前状态
    StateMachine_Change(psStateMachine,psStateMachine->CurSMOp->State);
}

/*******************************************************************************
  * 函数名  ：StateMchine_Handler
  * 功  能  ：状态机执行函数
  * 参  数  ：无
  * 返回值  ：无
  * 说  明  ：状态机Op执行函数
*******************************************************************************/
static void StateMchine_Handler(U32 arg)
{
    // 获取当前状态机
    StateMachine_ts *psStateMachine = (StateMachine_ts *)arg;

    // 执行回调函数
    U32 ret = psStateMachine->CurSMOp->pfStateHandler();

    // 根据不同返回值，执行不同操作
    switch(ret)
    {
    // 切换至下一状态
    case STATE_CTRL_NEXT:
        StateMachine_Change(psStateMachine,psStateMachine->CurSMOp->NextState);
    break;
    // 重试当前状态
    case STATE_CTRL_RETRY:
        // 重试次数累加
        psStateMachine->RetryCnt++;
        // 判断是否为定时重试
        if(psStateMachine->CurSMOp->Time != 0)
        {
            // 定时时间非0，定时重试
            OS_TimerRestartEx(&psStateMachine->sTimer,
                              psStateMachine->CurSMOp->Time,
                              StateMchine_TimingRetryHandler,
                              (U32)psStateMachine);
        }
        else
        {
            // 定时时间为0，立刻重试
            StateMachine_Change(psStateMachine,psStateMachine->CurSMOp->State);
        }
    break;
    // 保持当前状态，无操作
    default:
    break;
    }
}

/*******************************************************************************
  * 函数名  ：StateMchine_ChangeLastState
  * 功  能  ：状态机状态切换为上一次状态
  * 参  数  ：StateMachine_ts *psStateMachine：状态机
  * 返回值  ：无
  * 说  明  ：无
*******************************************************************************/
void StateMchine_ChangeLastState(StateMachine_ts *psStateMachine)
{
    StateMachine_Change(psStateMachine,psStateMachine->LastState);
}

/*******************************************************************************
  * 函数名  ：StateMachine_Change
  * 功  能  ：状态机状态改变
  * 参  数  ：StateMachine_ts *psStateMachine：状态机
  *          S16 state：将要改变的状态
  * 返回值  ：无
  * 说  明  ：无
*******************************************************************************/
void StateMachine_Change(StateMachine_ts *psStateMachine,S16 state)
{
    const StateMachineOps_ts *op = GetStateOps(psStateMachine,state);

    if(op != NULL)
    {

#ifdef STATE_MACHINE_DEBUG
        DEBUG("%s: change state to %s\r\n", psStateMachine->SMName,op->Name);
#endif
        if(psStateMachine->CurState != state)
        {
            // 状态机切换
            psStateMachine->LastState = psStateMachine->CurState;
            psStateMachine->CurState  = state;
            psStateMachine->RetryCnt  = 0;
            psStateMachine->CurSMOp   = op;
            OS_TimerStop(&psStateMachine->sTimer);
        }

        // 执行状态机处理
        OS_TaskAddEx(StateMchine_Handler,(U32)psStateMachine);
    }
}

/*******************************************************************************
  * 函数名  ：StateMachine_Recover
  * 功  能  ：状态机状态恢复
  * 参  数  ：StateMachine_ts *psStateMachine：状态机
  *          S16 state：将要恢复回的状态
  * 返回值  ：无
  * 说  明  ：仅恢复状态，不执行状态机回调函数。与StateMachine_Change不同
*******************************************************************************/
void StateMachine_Recover(StateMachine_ts *psStateMachine,S16 state)
{
    const StateMachineOps_ts *op = GetStateOps(psStateMachine,state);

    if(op)
    {

#ifdef STATE_MACHINE_DEBUG
        DEBUG("%s: recover state to %s\r\n",psStateMachine->SMName ,op->Name);
#endif
        if(psStateMachine->CurState != state)
        {
            //状态机参数恢复，不执行回调函数
            psStateMachine->LastState = psStateMachine->CurState;
            psStateMachine->CurState  = state;
            psStateMachine->RetryCnt  = 0;
            psStateMachine->CurSMOp   = op;
            OS_TimerStop(&psStateMachine->sTimer);
        }
    }
}

/*******************************************************************************
  * 函数名  ：StateMachine_GetCurState
  * 功  能  ：获取当前状态名称
  * 参  数  ：StateMachine_ts *psStateMachine：状态机
  * 返回值  ：当前状态
  * 说  明  ：无
*******************************************************************************/
S16 StateMachine_GetCurState(StateMachine_ts *psStateMachine)
{
    return psStateMachine->CurState;
}

/*******************************************************************************
  * 函数名  ：StateMachine_GetLastState
  * 功  能  ：获取上次状态名称
  * 参  数  ：StateMachine_ts *psStateMachine：状态机
  * 返回值  ：上次状态
  * 说  明  ：无
*******************************************************************************/
S16 StateMachine_GetLastState(StateMachine_ts *psStateMachine)
{
    return psStateMachine->LastState;
}

/*******************************************************************************
  * 函数名  ：StateMachine_GetRetryCount
  * 功  能  ：获取重试次数
  * 参  数  ：StateMachine_ts *psStateMachine：状态机
  * 返回值  ：当前状态的重试次数
  * 说  明  ：无
*******************************************************************************/
U16 StateMachine_GetRetryCount(StateMachine_ts *psStateMachine)
{
    return psStateMachine->RetryCnt;
}

/*******************************************************************************
  * 函数名  ：StateMachine_GetCurStateName
  * 功  能  ：获取当前状态名称
  * 参  数  ：StateMachine_ts *psStateMachine：状态机
  * 返回值  ：const char*：当前状态的名称（字符串）
  * 说  明  ：用于调试打印
*******************************************************************************/
const char* StateMachine_GetCurStateName(StateMachine_ts *psStateMachine)
{
    return psStateMachine->CurSMOp->Name;
}

/*******************************************************************************
  * 函数名  ：StateMchine_Init
  * 功  能  ：状态机初始化
  * 参  数  ：StateMachine_ts *psStateMachine：状态机句柄
  *          const char *SMName：状态机名称
  *          const StateMachineOps_ts *SMOpts：状态机回调函数表地址
  *          S16 SMOptCount：状态机回调函数表的元素个数
  * 返回值  ：无
  * 说  明  ：无
*******************************************************************************/
void StateMchine_Init(StateMachine_ts* psStateMachine,const char *SMName,const StateMachineOps_ts *SMOpts,S16 SMOptCount)
{
    if(psStateMachine != NULL && SMOpts != NULL)
    {
        psStateMachine->SMName = SMName;
        psStateMachine->FirstSMOp = SMOpts;
        psStateMachine->SMOpsCount = SMOptCount;
    }
}
